﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace System8Equations
{
    /// <summary>
    /// Given some inputs that vary, and some outputs to track, roll the dice and keep a log of what happens.
    /// </summary>
    public class EqnSeriesAccumulator
    {
        /// <summary>
        /// Initialize the equation tracker.
        /// </summary>
        public EqnSeriesAccumulator()
        {
        }

        /// <summary>
        /// Internal tracking class to watch what is changed.
        /// </summary>
        public class ColumnReference
        {
            public Func<double> Evaluator;
            private List<double> _values = new List<double>();

            public void Record()
            {
                _values.Add(Evaluator());
            }

            internal double[] AsArray()
            {
                return _values.ToArray();
            }
        }

        /// <summary>
        /// List of items we need to track as we roll the dice.
        /// </summary>
        private List<ColumnReference> _evals = new List<ColumnReference>();

        /// <summary>
        /// Each of these functions below will be called once to track what is happening. Use the
        /// returned reference to get the information back.
        /// </summary>
        /// <param name="getValue"></param>
        /// <returns></returns>
        public ColumnReference Watch(Func<double> getValue)
        {
            ColumnReference r = new ColumnReference();
            r.Evaluator = getValue;
            _evals.Add(r);
            return r;
        }

        /// <summary>
        /// Keep track of all actions we need to update.
        /// </summary>
        private List<Action> _valueUpdators = new List<Action>();

        /// <summary>
        /// Each of these actions is called at the start of every iteration. These actions
        /// should update our S8 stuff.
        /// </summary>
        /// <param name="setAValueOncePerIteration"></param>
        public void SetOnIteration(Action setAValueOncePerIteration)
        {
            _valueUpdators.Add(setAValueOncePerIteration);
        }

        /// <summary>
        /// Run the loop, and record the data. Old data is not cleared first!
        /// </summary>
        /// <param name="p"></param>
        public void Loop(int numberIterations)
        {
            for (int i = 0; i < numberIterations; i++)
            {
                ///
                /// First, randomize the input values
                /// 

                _valueUpdators.ForEach(a => a());

                ///
                /// Now, record everything
                ///

                _evals.ForEach(c => c.Record());
            }
        }

        /// <summary>
        /// This guy will return a double list of the results.
        /// </summary>
        /// <param name="refBottom"></param>
        /// <returns></returns>
        public double[] GetValueList(ColumnReference refBottom)
        {
            return refBottom.AsArray();
        }
    }
}
